#ifndef IMAGE_LIB_H
#define IMAGE_LIB_H

#include "FreeImage.h"

#if defined(__cplusplus)
extern "C" {            // Prevents name mangling of functions
#endif

typedef struct tagHSI{
	float h; //degree
	float s; //[0, 1]
	float i; //[0, 1]]
}HSITRIPLE;

extern HSITRIPLE rgb2hsi(RGBQUAD rgb);
extern RGBQUAD hsi2rgb(HSITRIPLE hsi);

//RGB image to HSI buffer
extern void rgb2hsi_img(FIBITMAP* dib, float* h, float* s, float* i);

//HSI buffer to RGB image
extern void hsi2rgb_img(FIBITMAP* dib, float* h, float* s, float* i);

//[0, 1] to [0, 255], data[h][w] to dst[h][w]
//type = 0, Hue; 1, Saturation; 2, Intensity
extern void
convert_hsi_data(float* data, int type, int w, int h, unsigned char* dst);

#define convert_hue_data(data, w, h, dst) \
	convert_hsi_data(data, 0, w, h, dst)

#define convert_saturat_data(data, w, h, dst) \
	convert_hsi_data(data, 1, w, h, dst)

#define convert_intense_data(data, w, h, dst) \
	convert_hsi_data(data, 2, w, h, dst)

extern FIBITMAP* open_img(char* path);

extern void read_img(FIBITMAP* dib, cpu_image* ptr);

extern void close_img(FIBITMAP* dib);

extern FIBITMAP* copy_img(FIBITMAP* dib);

/* use data[h][w] fill image */
extern void fill_image_data(FIBITMAP* dib, BYTE* data);

/* use data[h][w] fill image
 * data[index] is normalized data: [0, 1]
 * */
extern void fill_image_data_float(FIBITMAP* dib, float* data);

//flag: r = 0, g = 1, b = 2
//used r/g/b fill dst
extern void
fill_image_data_color(FIBITMAP* color, FIBITMAP* dst, int flag);

//flag: r = 0, g = 1, b = 2
//used src (gray) to fill color (rgb)
extern void
fill_color_image_gray(FIBITMAP* color, FIBITMAP* src, int flag);

extern
void color_image_sub(FIBITMAP* a, FIBITMAP* b, FIBITMAP* dst);

//read image data and write to data[h][w]
extern void init_image_data(FIBITMAP* dib, float* data);

//[0, 1]
extern void init_image_data_normalized(FIBITMAP* dib, float* data);

extern void init_image_datai(FIBITMAP* dib, int* data);
extern void init_image_datab(FIBITMAP* dib, unsigned char* data);

extern void init_image_databv(FIBITMAP* dib, BYTE* data);
extern void fill_image_datav(FIBITMAP* dib, BYTE* data);


//flag: r = 0, g = 1, b = 2
//used r/g/b fill data[h][w]
extern void
init_image_datab_color(FIBITMAP* color, unsigned char* data, int flag);


extern void init_image_center_data(FIBITMAP* dib, float* data);

//src[h][w] to center dst[h][w]
//dst may same address of src
extern void
move_data_to_center(float* src, float* dst, int w, int h);


/*
 * fb_width, fb_height: 窗口的宽，高
 * startx, starty: 相对于窗口的坐标
 * 把图片数据写入 framebuf 中
 * */
extern void image_update_frameBuf(FIBITMAP* dib,
		Color* frame_buf, int fb_width, int fb_height,
		int startx, int starty);

extern void image_data_update_frameBuf(BYTE* data, int w, int h,
	Color* frame_buf, int fb_width, int fb_height,
	int startx, int starty);

/* image_update_frameBuf 的另外一种写法 */
extern void show_image(void* dib, 
	cpu_image* ptr, int startx, int starty);

extern void show_image_data(BYTE* data, int w, int h,
	cpu_image* ptr, int startx, int starty);

/* 得到一幅图的直方图
 * unsigned int histo[256]
 * */
extern int get_histogram(FIBITMAP* dib, unsigned int* histo);

/*
  * in: float data[h][w], normalized data [0, 1]
  * out: unsigned int histo[256]
 * */
extern void
get_histogram_float(float* data, int width, int height, unsigned int* histo);

//min and max intensity of image
extern void image_get_intensity_range(FIBITMAP* dib, BYTE* min, BYTE* max);

/* show scaled image
 * open image from "file", and scaled to [h, w]
 * show_pos: right window index from 1 to 4
 * */
extern
void show_scaled_image(char* file, cpu_image *ptr, int w, int h, int show_pos);

extern
void show_scaled_dib(FIBITMAP* dib, cpu_image *ptr, int w, int h, int show_pos);

#define show_scaled(dib, pos) \
	show_scaled_dib(dib, &effect_data, effect_data.rw, effect_data.rh, pos)

//show file at window(pos)
#define show_scaled_img(file, pos) \
	show_scaled_image(file, &effect_data, w, h, pos)

//BYTE data[h][w]: image data
//scaled to nw * nh, show at window pos
extern void show_scaled_data_common(
	BYTE* data, cpu_image *ptr,
	int w, int h, int pos, int nw, int nh);

#define show_scaled_data(data, pos, nw, nh) \
	show_scaled_data_common(data, &effect_data, w, h, pos, nw, nh)

#define show_scaled_datas(data, pos) \
	show_scaled_data(data, pos, effect_data.rw, effect_data.rh)

/*
 * ori to chg with specified filter algorithm
 * */
typedef void (*pf_show_handled_image)(FIBITMAP* ori, FIBITMAP* chg,
	int filter_type, int dim, void* user_data);

/* show scaled filtered image in right window(show_pos)
 *
 * in:
 *	file: image file name
 *	show_pos: right window index from 1 to 4
 *	w, h: window size
 *	filter_type: user define
 *	dim: dimension of spatial filter
 *	user_data: in-out user data
 * */
extern
void show_filtered_image(char* file, cpu_image *ptr, int w, int h, int show_pos,
	pf_show_handled_image filter, int filter_type, int dim, void* user_data);

//show scaled filtered image at window(pos), type = filter_type
#define show_filtered_image_nodata(file, pos, filter, type, dim) \
	show_filtered_image(file, &effect_data, w, h, pos, filter, type, dim, NULL)

//if WhitIsZero, invert it
extern void binary_image_invert(FIBITMAP* dib);


#if defined(__cplusplus)
}
#endif

#endif
